#include <climits> // for LONG_MAX
#include "Token.h"

// Initialize the token names vector, used for console output
std::string Token::tokenNames[TOKEN_SENTRY] = {
	"UNKNOWN_TOKEN", "UNTERMINATED_COMMENT", "NUM_CONST_TOO_LARGE",
	"ERROR_CHAR_CONST_LEN",
	"IDENTIFIER", "NUM_CONST", "CHAR_CONST", 
	"RIGHT_PARENTHESES", "LEFT_PARENTHESES", "SEMICOLON", "PLUS", "MINUS", "ASTERISK", 
	"DIVIDE", "MOD", "ASSIGNMENT", "LT", "LOGIC_NOT", "LOGIC_OR", 
	"LOGIC_AND", "GT", "EQUAL", "LTE", "GTE", "NOT_EQ", 
	"RIGHT_BRACKET", "LEFT_BRACKET", "RIGHT_BRACE", "LEFT_BRACE", "COMMA", 
	"MAIN", "INT", "CHAR", "VOID", "IF", 
	"ELSE", "WHILE", "RETURN", "SCANF", "PRINTF",
	"END_OF_FILE" };

/**
 * Constructor
 * @param optional TokenType of the new token
 */
Token::Token(TokenType tokenType) : type(tokenType) { }

/**
 * Destructor
 */
Token::~Token() { }

/**
 * Setter for the type of token
 * @param the new TokenType of the token
 */
void Token::setType(TokenType type) {	
	this->type = type;
}

/**
 * Getter for the type of the token
 * @return the Token's TokenType
 */
TokenType Token::getType() {
	return type;
}

/**
 * Setter for the value of the token
 * @param a string with the value of the token as extracted from the src file
 * This function silently ignores attempts to set value on most types of tokens
 * only errors, character constants, idetifiers and numerical constants can have
 * a value.
 */
void Token::setValue(std::string myValue) {
	// all errors, identifiers, numerical constants and char constants
	if(type <= TK_CHAR_CONST) {
		sValue = myValue;
	} 
	
	if(type==TK_NUM) {
		// check that the numerical constant is not too big	
		unsigned long lValue=0L;
		for(std::size_t i=0;i<myValue.length();++i) {
			lValue = lValue*10 + (myValue[i]-'0');
			if(lValue > LONG_MAX) {
				type = TK_ERROR_NUM_CONST_TOO_LARGE;
				break;
			}
		}
	}
}

/**
 * Getter for the token's value
 * @return the string which was extracted from the source file
 * This function is only meaningful for errors, identifiers, numerical constants
 * and character constants
 */
std::string Token::getValue() {
	return sValue;
}

/**
 * Setter for the line number where this token was extracted
 * @param line number
 */
void Token::setLineNum(int lineNum) {
	lineNumber=lineNum;
}

/**
 * Getter for line number
 * @return the line number where the token was extracted
 */
int Token::getLineNum() {
	return lineNumber;
}

/**
 * A function which makes it possible to overload the insertion operator
 * without using a 'friend' function
 * @param a reference to a stl ostream 
 */
std::ostream& Token::inserter(std::ostream &os) const {
	os << tokenNames[type];
	
	if( type==TK_IDENTIFIER || type==TK_NUM || type==TK_CHAR_CONST )
		os << "[\"" << sValue << "\"]";

	return os;
}
